package cn.dubito.sshl.idx.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.springframework.beans.factory.annotation.Autowired;

import cn.dubito.sshl.common.PageModel;
import cn.dubito.sshl.idx.LuceneDao;


/**
 * LuceneDaoImpl
 */
public abstract class LuceneDaoImpl implements LuceneDao {
	@Autowired
	private IndexWriterConfig indexWriterConfig;
	@Autowired
	protected Analyzer analyzer;
	@Autowired
	private Formatter formatter;
	/** 获取IndexWriter */
	private IndexWriter getIndexWriter() {
		try{
			File dir = new File(getDirectoryPath());
			/** 判断文件路径是否存在 */
			if (!dir.exists()){
				dir.mkdirs();
			}
			return new IndexWriter(FSDirectory.open(dir), indexWriterConfig);
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 添加文档
	 * @param document文档
	 */
	public void save(Document document){
		try(IndexWriter indexWriter = getIndexWriter()){
			indexWriter.addDocument(document);
			indexWriter.commit();
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 修改文档
	 * @param field
	 * @param value
	 * @param document
	 */
	public void update(String field, String value, Document document){
		try(IndexWriter indexWriter = getIndexWriter()){
			indexWriter.updateDocument(new Term(field, value), document);
			indexWriter.commit();
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 删除文档
	 * @param field
	 * @param value
	 */
	public void delete(String field, String value){
		try(IndexWriter indexWriter = getIndexWriter()){
			indexWriter.deleteDocuments(new Term(field, value));
			indexWriter.commit();
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 删除全部文档
	 */
	public void deleteAll(){
		try(IndexWriter indexWriter = getIndexWriter()){
			indexWriter.deleteAll();
			indexWriter.commit();
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 检索文档
	 * @param queryStr
	 * @param num
	 * @return
	 */
	public List<Document> find(String queryStr, int num){
		try{
			QueryParser queryParser = new QueryParser(Version.LUCENE_40, null, analyzer);
			return find(queryParser.parse(queryStr), num);
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 检索文档
	 * @param queryStr
	 * @param num
	 * @return
	 */
	public List<Document> find(Query query, int num){
		try(IndexReader indexReader = DirectoryReader.open(FSDirectory.open(new File(getDirectoryPath())))){
			IndexSearcher indexSearcher = new IndexSearcher(indexReader);
			TopDocs topDocs = indexSearcher.search(query, num);
			List<Document> documents = new ArrayList<>(); 
			for (ScoreDoc scoreDoc : topDocs.scoreDocs){
				documents.add(indexSearcher.doc(scoreDoc.doc));
			}
			return documents;
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 分页检索文档
	 * @param queryStr
	 * @param pageModel
	 * @return
	 */
	public List<Document> findByPage(String queryStr, PageModel pageModel){
		try{
			QueryParser queryParser = new QueryParser(Version.LUCENE_40, null, analyzer);
			return findByPage(queryParser.parse(queryStr), pageModel);
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 分页检索文档
	 * @param query
	 * @param pageModel
	 * @return
	 */
	public List<Document> findByPage(Query query, PageModel pageModel){
		try(IndexReader indexReader = DirectoryReader.open(FSDirectory.open(new File(getDirectoryPath())))){
			IndexSearcher indexSearcher = new IndexSearcher(indexReader);
			
			TopDocs topDocs = indexSearcher.search(query, pageModel.getPageIndex() * pageModel.getPageSize());
			/** 设置总记录条数*/
			pageModel.setRecordCount(topDocs.totalHits);
			List<Document> documents = new ArrayList<>(); 
			for (int i = pageModel.getStartRow(); i < topDocs.scoreDocs.length; i++){
				ScoreDoc scoreDoc = topDocs.scoreDocs[i];
				documents.add(indexSearcher.doc(scoreDoc.doc));
			}
			return documents;
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 获取高亮对象
	 * @param queryStr
	 * @param num
	 * @return
	 */
	public Highlighter getHighlighter(String queryStr, int num){
		try{
			QueryParser queryParser = new QueryParser(Version.LUCENE_40, null, analyzer);
			QueryScorer scorer = new QueryScorer(queryParser.parse(queryStr));
			Highlighter highlighter = new Highlighter(formatter, scorer);
			/** 设置文本截断 */
			highlighter.setTextFragmenter(new SimpleSpanFragmenter(scorer, num));
			return highlighter;
		}catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}
	/** 提供一个抽象方法 */
	public abstract String getDirectoryPath();
}